home *** CD-ROM | disk | FTP | other *** search
/ Aminet 49 / Aminet 49 (2002)(GTI - Schatztruhe)[!][Jun 2002].iso / Aminet / dev / misc / FlexCat_Src.lha / flexcat.c < prev    next >
C/C++ Source or Header  |  2002-02-14  |  66KB  |  2,910 lines

  1.  
  2. /*****************************************************************
  3. **                                                              **
  4. ** If you use GoldED or any other text editor featuring folding **
  5. ** you may want to set up "///" as fold opening phrase, and     **
  6. ** "//|" as closing one, as this source is using it.            **
  7. **                                                              **
  8. **                                                Marcin        **
  9. **                                                              **
  10. *****************************************************************/
  11.  
  12. /* $Id: flexcat.c,v 1.21 2002/02/14 19:07:23 carlos Exp $ */
  13.  
  14. #define __amigados
  15.  
  16. /// README
  17. /*
  18.  
  19.     FlexCat.c:  The flexible catalog creator
  20.  
  21.     This program is distributed in the hope that it will be useful,
  22.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  23.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  24.  
  25.     Ok, this is nothing special. It grabs a catalog translation and a
  26.     catalog description file and produces catalogs and the source to
  27.     handle them. What is it else than lots of other programs?
  28.  
  29.     The difference is, that YOU determine what source FlexCat produces.
  30.     Another file is scanned by FlexCat to produce code. This file contains
  31.     some c-string like special characters (%v for version for example)
  32.     You can edit this file and modify it as you want. So FlexCat can produce
  33.     C source as well as Assembler, Oberon, Modula 2, E, ...
  34.  
  35. */
  36. //|
  37.  
  38. #define VERSION 2
  39. #define REVISION 5
  40. #define VERS       "FlexCat 2.5"
  41.  
  42. #ifdef __amigados
  43.  
  44.  #ifdef _M68060
  45.    #define _CPU "[68060]"
  46.  #else
  47.    #ifdef _M68040
  48.      #define _CPU "[68040]"
  49.    #else
  50.      #ifdef _M68030
  51.        #define _CPU "[68030]"
  52.      #else
  53.        #ifdef _M68020
  54.          #define _CPU "[68020]"
  55.        #else
  56.          #ifdef _M68010
  57.            #define _CPU "[68010]"
  58.          #else
  59.            #define _CPU "[680x0]"
  60.          #endif
  61.        #endif
  62.      #endif
  63.    #endif
  64.  #endif
  65.  
  66. #define VSTRING  VERS " " _CPU " " __DATE__
  67. #else
  68. #define VSTRING  VERS
  69. #endif
  70.  
  71. #define VERSTAG  "$VER: " VSTRING
  72.  
  73. /// Includes and defines
  74.  
  75. #include <stdlib.h>
  76. #include <stdio.h>
  77. #include <string.h>
  78. #include <ctype.h>
  79. #include <time.h>
  80. #ifdef __amigados
  81.   #include <dos.h>
  82. #endif
  83. #include "flexcat_cat.h"
  84.  
  85. #if ((defined(_DCC) && defined(AMIGA))       ||     \
  86.      (defined(__SASC) && defined(_AMIGA)))      &&  \
  87.     !defined(__amigados)
  88. #define __amigados
  89. #endif
  90.  
  91. #if defined(__amigados)
  92. #include <exec/types.h>
  93. #if defined(_DCC) || defined(__SASC) || defined(__GNUC__)
  94. #include <proto/exec.h>
  95. #include <proto/dos.h>
  96. #include <proto/intuition.h>
  97. #include <proto/utility.h>
  98. #else
  99. #include <clib/exec_protos.h>
  100. #include <clib/dos_protos.h>
  101. #include <clib/utility_protos.h>
  102. #endif
  103.  
  104. #ifdef tolower
  105. #undef tolower
  106. #endif
  107. #define tolower         ToLower
  108. #define stricmp(s,t)    Stricmp((char *) (s), (char *) (t))
  109. #define strnicmp(s,t,l) Strnicmp((char *) (s), (char *) (t), l)
  110.  
  111. #endif
  112.  
  113.  
  114. #ifndef FALSE
  115. #define FALSE 0
  116. #endif
  117. #ifndef TRUE
  118. #define TRUE (!FALSE)
  119. #endif
  120.  
  121.  
  122. #define MAXPATHLEN 512
  123. #define FLEXCAT_SDDIR "FLEXCAT_SDDIR"
  124. #if defined(__amigados)
  125. #define DEFAULT_FLEXCAT_SDDIR "PROGDIR:lib"
  126. #else
  127. #define DEFAULT_FLEXCAT_SDDIR "lib"
  128. #endif
  129.  
  130. #if defined(__amigados)
  131. #define MAX_PREFS_LEN 512
  132. #define FLEXCAT_PREFS "flexcat.prefs"
  133. char    prefs_sddir[MAXPATHLEN] = "\0";
  134. #endif
  135.  
  136.  
  137. #ifndef MAKE_ID
  138. #define MAKE_ID(a,b,c,d)        \
  139.         ((ULONG) (a)<<24 | (ULONG) (b)<<16 | (ULONG) (c)<<8 | (ULONG) (d))
  140. #endif
  141.  
  142. #ifndef ULONG
  143. #define ULONG unsigned long
  144. #endif
  145.  
  146. //|
  147. /// Structs
  148.  
  149. enum StringTypes {
  150.     TYPE_C,         /*  Produce C strings                   */
  151.     TYPE_ASSEMBLER, /*  Produce Assembler strings           */
  152.     TYPE_OBERON,    /*  Produce Oberon strings              */
  153.     TYPE_E,         /*  Produce E strings. (Oops, thought   */
  154.                     /*  it allows only 32 bit integers? ;-) */
  155.     TYPE_NONE       /*  Simple strings                      */
  156. };
  157.  
  158.  
  159. enum OutputModes {
  160.     OutputMode_None,    /*  Nothing written yet                 */
  161.     OutputMode_Bin,     /*  Last character written was binary   */
  162.     OutputMode_Ascii    /*  Last character written was Ascii    */
  163. };
  164.  
  165. struct CatString
  166. { struct CatString *Next;
  167.   char *CD_Str;
  168.   char *CT_Str;
  169.   char *ID_Str;
  170.   int MinLen, MaxLen, ID, Nr;
  171.   int NotInCT;          /* If string is not present we write NEW    */
  172.                         /* while updating CT file, for easier work. */
  173.  
  174. };
  175.  
  176. struct CDLine
  177. { struct CDLine *Next;
  178.   char *Line;
  179. };
  180.  
  181. struct CatalogChunk
  182. { struct CatalogChunk *Next;            /* struct CatalogChunk *Next */
  183.   ULONG ID;
  184.   char *ChunkStr;
  185. };
  186.  
  187. struct CatString *FirstCatString = NULL;  /*  First catalog string            */
  188. struct CDLine *FirstCDLine = NULL;        /*  First catalog description line  */
  189. struct CatalogChunk *FirstChunk = NULL;   /*  List of catalog chunks          */
  190.  
  191. char *BaseName   = "";              /*  Basename of catalog description */
  192. char *Language   = "english";       /*  Language of catalog description */
  193. int  CatVersion  = 0;               /*  Version of catalog to be opened */
  194. int  LengthBytes = 0;               /*  Number of bytes to preceed a    */
  195.                                     /*  created string and containing   */
  196.                                     /*  its length.                     */
  197. char *CatLanguage      = NULL;      /*  Language of catalog translation */
  198. char *CatVersionString = NULL;      /*  version string of catalog       */
  199.                                     /*  translation (## version)        */
  200. char *CatRcsId = NULL;              /*  rcs ID of catalog translation   */
  201.                                     /*  (## rcsid)                      */
  202. char *CatName = NULL;               /*  name of catalog translation     */
  203. int  CodeSet = 0;                   /*  Codeset of catalog translation  */
  204. int  NumStrings = 0;                /*  Number of catalog strings       */
  205. int  LongStrings = TRUE;            /*  Generate long or short strings  */
  206.  
  207. char *ScanFile;                     /*  File currently scanned          */
  208. int  ScanLine;                      /*  Line currently scanned          */
  209.  
  210. int  GlobalReturnCode = 0;          /*  Will be 5, if warnings appear    */
  211. int  WarnCTGaps = FALSE;            /*  Warn missing symbols in CT       */
  212.                                     /*  file.                            */
  213. int  NoOptim = FALSE;               /*  Put string into catalog even     */
  214.                                     /*  if translation is equal to       */
  215.                                     /*  description.                     */
  216. int  Fill    = FALSE;               /*  It translation of given string   */
  217.                                     /*  is missing or it's empty, write  */
  218.                                     /*  string descriptor from #?.cd     */
  219.                                     /*  file instead.                    */
  220. int  DoExpunge = FALSE;             /*  If TRUE FlexCat will do AVAIL    */
  221.                                     /*  FLUSH alike after catalog save   */
  222. int  NoBeep = FALSE;                /*  if TRUE, FlexCat won't call      */
  223.                                     /*  DisplayBeep() any longer         */
  224. int  Quiet   = FALSE;               /*  Forces FlexCat to shut up        */
  225.  
  226. int  NumberOfWarnings = 0;          /* We count warnings to be smart     */
  227.                                     /* and not to do Beep bombing, but   */
  228.                                     /* call DisplayBeep() only once      */
  229. int  CT_Scanned = FALSE;            /* If TRUE, and we are going to      */
  230.                                     /* write new #?.ct file, then user   */
  231.                                     /* surely updates own #?.ct file     */
  232.                                     /* so we should write ***NEW***      */
  233.                                     /* whenever necessary.               */
  234. int  LANGToLower = TRUE;            /* Shall we do ToLower() on lang's   */
  235.                                     /* name? Some #?.language seems to   */
  236.                                     /* be broken, so we allow workaround */
  237. int  NoBufferedIO = FALSE;          /* Shall we do buffered IO           */
  238. int  buffer_size = 2048;            /* Size of the IO buffer             */
  239. int  Modified = FALSE;              /* Shall we write the catalog ONLY   */
  240.                                     /* if #?.catalog is younger than     */
  241.                                     /* #?.c(d|t) files?                  */
  242.  
  243. #define MAX_NEW_STR_LEN 25
  244. char Msg_New[MAX_NEW_STR_LEN]    = "***NEW***";
  245.                                     /*  new strings in updated #?.ct    */
  246.  
  247. int  CopyNEWs = FALSE;
  248. char Old_Msg_New[MAX_NEW_STR_LEN] = "; ***NEW***";
  249.  
  250.                                     /*  old newstring (above) used in old   */
  251.                                     /* CT file. Now we look if it's present */
  252.                                     /* and copy it into new CT if user does */
  253.                                     /* upgrade (flexcat CD CT newctfile CT  */
  254.  
  255. int  NoSpace = FALSE;               /* do want to strip the space usually  */
  256.                                     /* placed between ';' and original     */
  257.                                     /* string?                             */
  258.  
  259.  
  260. char VersTag[] = VERSTAG;
  261. char VString[] = VSTRING " by Jochen Wiedmann and Marcin Orlowski";
  262. char EString[] = "E-mail: carlos@amiga.com.pl or marcin@orlowski.com WWW: http://amiga.com.pl/flexcat/";
  263. //|
  264.  
  265. /// FUNC: ReadPrefs
  266. #if defined(__amigados)
  267.  
  268. char ReadPrefs(void)
  269. {
  270. enum{ SDDIR,
  271.       MSG_NEW,
  272.       WARNCTGAPS,
  273.       NOOPTIM,
  274.       FILL,
  275.       FLUSH,
  276.       NOBEEP,
  277.       QUIET,
  278.       NOLANGTOLOWER,
  279.       NOBUFFEREDIO,
  280.       MODIFIED,
  281.       COPYMSGNEW,
  282.       OLDMSGNEW,
  283.       NOSPACE,
  284.       ARGS_COUNT
  285.     };
  286.  
  287. char   template[] = "SDDIR/K,MSG_NEW/K,WARNCTGAPS/S,NOOPTIM/S,FILL/S,FLUSH/S,NOBEEP/S,QUIET/S,NOLANGTOLOWER/S,NOBUFFEREDIO/S,MODIFIED/S,COPYMSGNEW/S,OLDMSGNEW/K,NOSPACE/S";
  288. LONG   Results[ARGS_COUNT] = {0};
  289. char   result = FALSE;
  290. char   *prefs;
  291. struct RDArgs *rda;
  292. struct RDArgs *rdargs;
  293.  
  294.   if(prefs = getenv(FLEXCAT_PREFS))
  295.     {
  296.     prefs = realloc(prefs, strlen(prefs)+1);
  297.     strcat(prefs, "\n");
  298.  
  299.     if(rda = AllocDosObject(DOS_RDARGS, TAG_DONE))
  300.        {
  301.        rda->RDA_Source.CS_Buffer = prefs;
  302.        rda->RDA_Source.CS_Length = strlen(prefs);
  303.        rda->RDA_Source.CS_CurChr = 0;
  304.        rda->RDA_Flags |= RDAF_NOPROMPT;
  305.  
  306.        if(rdargs = ReadArgs(template, Results, rda))
  307.          {
  308.          if(Results[SDDIR])
  309.            strncpy(prefs_sddir, (char *)Results[SDDIR], MAXPATHLEN);
  310.  
  311.          if(Results[MSG_NEW])
  312.            strncpy(Msg_New, (char *)Results[MSG_NEW], MAX_NEW_STR_LEN);
  313.  
  314.          WarnCTGaps   = Results[WARNCTGAPS];
  315.          NoOptim      = Results[NOOPTIM];
  316.          Fill         = Results[FILL];
  317.          DoExpunge    = Results[FLUSH];
  318.          NoBeep       = Results[NOBEEP];
  319.          Quiet        = Results[QUIET];
  320.          LANGToLower  = Results[NOLANGTOLOWER];
  321.          Modified     = Results[MODIFIED];
  322.          NoBufferedIO = Results[NOBUFFEREDIO];
  323.          CopyNEWs     = Results[COPYMSGNEW];
  324.          NoSpace      = Results[NOSPACE];
  325.          if(Results[OLDMSGNEW])
  326.            sprintf(Old_Msg_New, "; %s", (char *)Results[OLDMSGNEW]);
  327.  
  328.          FreeArgs(rdargs);
  329.  
  330.          result = TRUE;
  331.          }
  332.        else
  333.          {
  334.          fputs((char *)msgPrefsError, stderr);
  335.          fputs((char *)template, stderr);
  336.          fputs((char *)"\n", stderr);
  337.          DisplayBeep(NULL);
  338.          }
  339.  
  340.        FreeDosObject(DOS_RDARGS, rda);
  341.        }
  342.      else
  343.        {
  344.        fputs("Error processing prefs.\nCan't AllocDosObject()\n", stderr);
  345.        }
  346.  
  347.     free(prefs);
  348.     }
  349.  
  350.   return(result);
  351. }
  352.  
  353. #endif
  354. //|
  355.  
  356. /// FUNC: MyExit
  357. void MyExit (int Code)
  358. {
  359.  
  360. #if defined(__amigados)
  361.  
  362.   if(((NumberOfWarnings > 0) ||(Code !=0)) && (!NoBeep))
  363.      DisplayBeep(NULL);
  364.  
  365. #endif
  366.  
  367. #if defined(_DCC)
  368.   //STATIC __autoexit VOID _STDCloseFlexCatCatalog(VOID)
  369. #elif defined(__SASC)
  370.   //VOID _STDCloseFlexCatCatalog(VOID)
  371. #elif defined(__GNUC__)
  372.   //STATIC VOID _STDCloseFlexCatCatalog(VOID)
  373. #else
  374.   CloseFlexCatCatalog();      /* we need to close something... */
  375. #endif
  376.  
  377.     exit(Code);
  378. }
  379. //|
  380.  
  381. /// FUNC: stricmp
  382.  
  383. // quick stricmp
  384.  
  385. #ifndef __amigados
  386. int stricmp( char *str1, char *str2 )
  387. {
  388.   register int i;
  389.  
  390.     for(i = 0;; i++)
  391.        {
  392.        int a = tolower( (int)*str1 );
  393.        int b = tolower( (int)*str2 );
  394.  
  395.        if( !a || !b )
  396.            break;
  397.  
  398.        if( a != b )
  399.            return( 1 );
  400.  
  401.        str1++;
  402.        str2++;
  403.        }
  404.  
  405.     return( 0 );
  406. }
  407. #endif
  408.  
  409. //|
  410. /// FUNC: strnicmp
  411.  
  412. // quick strnicmp
  413.  
  414. #ifndef __amigados
  415. int strnicmp( char *str1, char *str2, int len )
  416. {
  417.   register int i;
  418.  
  419.     for(i = 0; i < len; i++)
  420.        {
  421.        int a = tolower( (int)*str1 );
  422.        int b = tolower( (int)*str2 );
  423.  
  424.        if( !a || !b )
  425.            break;
  426.  
  427.        if( a != b )
  428.            return( 1 );
  429.  
  430.        str1++;
  431.        str2++;
  432.        }
  433.  
  434.     return( 0 );
  435. }
  436. #endif
  437.  
  438. //|
  439.  
  440. /// FUNC: Swappers...
  441.  
  442.  
  443. unsigned short (*SwapWord)(unsigned short r) = NULL;
  444. unsigned long  (*SwapLong)(unsigned long r)  = NULL;
  445.  
  446.  
  447. unsigned short SwapWord21(unsigned short r)
  448. {
  449.     return (unsigned short)((r>>8) + (r<<8));
  450. }
  451. unsigned short SwapWord12(unsigned short r)
  452. {
  453.     return r;
  454. }
  455. unsigned long SwapLong4321(unsigned long r)
  456. {
  457.     return  ((r>>24) & 0xFF) + (r<<24) + ((r>>8) & 0xFF00) + ((r<<8) & 0xFF0000);
  458. }
  459. unsigned long SwapLong1234(unsigned long r)
  460. {
  461.     return r;
  462. }
  463.  
  464. //|
  465. /// FUNC: SwapChoose
  466. int SwapChoose(void)
  467. {
  468. unsigned short w;
  469. unsigned long  d;
  470.  
  471.   strncpy((char *)&w, "\1\2", 2);
  472.   strncpy((char *)&d, "\1\2\3\4", 4);
  473.  
  474.   if (w == 0x0201)
  475.     SwapWord = SwapWord21;
  476.   else if (w == 0x0102)
  477.     SwapWord = SwapWord12;
  478.   else
  479.     return 0;
  480.  
  481.   if (d == 0x04030201)
  482.     SwapLong = SwapLong4321;
  483.   else if (d == 0x01020304)
  484.     SwapLong = SwapLong1234;
  485.   else
  486.     return 0;
  487.  
  488.   return 1;
  489. }
  490. //|
  491.  
  492. /// FUNC: ShowError
  493.  
  494. /*
  495.     This shows an error message and terminates
  496. */
  497. void ShowError(const char *msg, ...)
  498. {
  499. char **ptr = (char **) &msg;
  500.  
  501. //  if(!Quiet)
  502.     {
  503.     fprintf(stderr, ptr[0], ptr[1], ptr[2], ptr[3], ptr[4]);
  504.     putc('\n', stderr);
  505.     }
  506.  
  507. #if defined(__amigados)
  508.   NumberOfWarnings++;
  509. #endif
  510.  
  511.   MyExit(10);
  512. }
  513. //|
  514. /// FUNC: MemError
  515.  
  516. /*
  517.     This shows the message: Memory error.
  518. */
  519. void MemError(void)
  520.  
  521. {
  522.   ShowError(msgMemoryError, NULL);
  523. }
  524. //|
  525. /// FUNC: ShowWarn
  526.  
  527. /*
  528.     This shows a warning
  529. */
  530. void ShowWarn(const char *msg, ...)
  531.  
  532. { char **ptr = (char **) &msg;
  533.  
  534.   if(!Quiet)
  535.     {
  536.     fprintf(stderr, (char *) msgWarning, ScanFile, ScanLine);
  537.     fprintf(stderr, ptr[0], ptr[1], ptr[2], ptr[3], ptr[4]);
  538.     putc('\n', stderr);
  539.     }
  540.  
  541.   NumberOfWarnings++;
  542.   GlobalReturnCode = 5;
  543. }
  544. //|
  545. /// FUNC: AllocString
  546.  
  547. /*
  548.     This allocates a string
  549. */
  550. char *AllocString(const char *str)
  551.  
  552. { char *ptr;
  553.  
  554.   if (!(ptr = malloc(strlen(str)+1)))
  555.   { MemError();
  556.   }
  557.   strcpy(ptr, str);
  558.   return(ptr);
  559. }
  560. //|
  561. /// FUNC: Add catalog chunk
  562.  
  563. /*
  564.     This adds a new catalog chunk to the list of catalog
  565.     chunks.
  566. */
  567. char *AddCatalogChunk(char *ID, const char *string)
  568. {
  569.   struct CatalogChunk *cc, **ccptr;
  570.  
  571.   if (!(cc = malloc(sizeof(*cc))))
  572.   { MemError();
  573.   }
  574.   cc->Next = NULL;
  575.   cc->ID = *((ULONG *) ID);
  576.   cc->ChunkStr = AllocString(string);
  577.  
  578.   /*
  579.       Put the new chunk to the end of the chunk list.
  580.   */
  581.   for (ccptr = &FirstChunk;  *ccptr != NULL;  ccptr = &(*ccptr)->Next)
  582.   {
  583.   }
  584.   *ccptr = cc;
  585.   return(cc->ChunkStr);
  586. }
  587. //|
  588. /// FUNC: gethex
  589. /*
  590.     This translates a hex character.
  591. */
  592. int gethex(int c)
  593. {
  594.   if (c >= '0'  &&  c <= '9')
  595.   { return(c - '0');
  596.   }
  597.   else if (c >= 'a'  &&  c <= 'f')
  598.   { return(c - 'a' + 10);
  599.   }
  600.   else if (c >= 'A'  &&  c <= 'F')
  601.   { return(c - 'A' + 10);
  602.   }
  603.   ShowWarn(msgExpectedHex);
  604.   return(0);
  605. }
  606. //|
  607. /// FUNC: getoctal
  608.  
  609. /*
  610.     This translates an octal digit.
  611. */
  612. int getoctal(int c)
  613. {
  614.  
  615.   if (c >= '0'  &&  c <= '7')
  616.     {
  617.     return(c - '0');
  618.     }
  619.  
  620.   ShowWarn(msgExpectedOctal);
  621.   return(0);
  622.  
  623. }
  624. //|
  625. /// FUNC: ReadLine
  626.  
  627. /*
  628.     Reading a line is somewhat complicated in order to allow lines of any
  629.     length.
  630.  
  631.     Inputs: fp           - the file, where the input comes from
  632.             AllowComment - TRUE, if a leading semicolon should force to
  633.                            interpret the line as a comment line
  634. */
  635. #define BUFSIZE 4096
  636. char *ReadLine(FILE *fp, int AllowComment)
  637. {
  638.  
  639.   char *OldLine, *NewLine = NULL;
  640.   int c = '\0';
  641.   int Len = 0, LineLen = 0;
  642.   int FirstChar = TRUE;
  643.   int BackslashSeen   = FALSE;
  644.   int BackslashSeenOn = 0;     /* position the last backslash was seen on */
  645.   int CommentLine = FALSE;     /* if TRUE we should ignore normally treat trailing \'s */
  646.  
  647.   while(c != EOF)
  648.     {
  649.     if(Len+10 > LineLen)
  650.       {
  651.       OldLine = NewLine;
  652.       if(!(NewLine = malloc(LineLen+BUFSIZE)))
  653.         MemError();
  654.  
  655.       strncpy(NewLine, OldLine, LineLen);
  656.       if(OldLine)
  657.         free(OldLine);
  658.  
  659.       LineLen += BUFSIZE;
  660.       }
  661.  
  662.     c = getc(fp);
  663.  
  664.     if(FirstChar)
  665.       {
  666.       if(c == EOF)
  667.         {
  668.         free(NewLine);
  669.         return(NULL);
  670.         }
  671.  
  672.       if(c == ';')
  673.         {
  674.         CommentLine = TRUE;
  675.         }
  676.  
  677.       FirstChar = FALSE;
  678.       }
  679.  
  680.     switch(c)
  681.       {
  682.       case '\r':
  683.         break;
  684.  
  685.       case '\n':
  686.         ++ScanLine;
  687.         if(BackslashSeen)
  688.           {
  689.           NewLine[Len++] = c;
  690.           BackslashSeen = FALSE;
  691.           break;
  692.           }
  693.         c = EOF;
  694.  
  695.       case EOF:
  696.         break;
  697.  
  698.                                  /*  Let's check for trailing \\ */
  699.       case '\\':
  700.         {
  701.         if(!CommentLine)
  702.           {
  703.           if(BackslashSeen)
  704.             {
  705.             if(BackslashSeenOn == (Len-1))
  706.               {
  707.               BackslashSeen = FALSE;
  708.               NewLine[Len++] = c;
  709.               break;
  710.               }
  711.             }
  712.  
  713.           BackslashSeen = TRUE;
  714.           BackslashSeenOn = Len;
  715.           }
  716.  
  717.         NewLine[Len++] = c;
  718.         break;
  719.         }
  720.  
  721.  
  722.       default:
  723.         BackslashSeen = FALSE;
  724.         NewLine[Len++] = c;
  725.       }
  726.     }
  727.  
  728.   NewLine[Len] = '\0';
  729.  
  730.   return(NewLine);
  731.  
  732. }
  733. //|
  734. /// FUNC: OverSpace
  735.  
  736. /*
  737.     This removes trailing blanks.
  738. */
  739. void OverSpace(char **strptr)
  740.  
  741. { int c;
  742.  
  743.   while ((c = **strptr) == ' '  ||  c == '\t')
  744.   { (*strptr)++;
  745.   }
  746. }
  747. //|
  748.  
  749. /// FUNC: Expunge
  750.  
  751. void Expunge(void)
  752. {
  753. #if defined(__amigados)
  754.  
  755.  
  756.   if(DoExpunge)
  757.     {
  758. #ifdef __EXPUNGE_ALL__
  759.     APTR Memory;
  760.  
  761.     if(Memory = AllocMem(-1, NULL))
  762.        FreeMem(Memory, -1);                // just in case ;-)
  763. #else
  764.  
  765. #pragma libcall LocaleBase localeExpunge 12 00
  766. VOID localeExpunge(VOID);
  767.  
  768.     struct Library    *LocaleBase;
  769.  
  770.     if(LocaleBase = OpenLibrary("locale.library", 0))
  771.        {
  772.        localeExpunge();
  773.        CloseLibrary(LocaleBase);
  774.        }
  775.  
  776. #endif
  777.     }
  778. #endif
  779.  
  780. }
  781.  
  782. //|
  783.  
  784. /// FUNC: ReadChar
  785.  
  786. /*
  787.     ReadChar scans an input line translating the backslash characters.
  788.  
  789.     Inputs: char *  - a pointer to a stringpointer; the latter points to the
  790.                       next character to be read and points behind the read
  791.                       bytes after executing ReadChar
  792.             dest    - a pointer to a buffer, where the read bytes should be
  793.                       stored
  794.  
  795.     Result: number of bytes that are written to dest (between 0 and 2)
  796. */
  797. int ReadChar(char **strptr, char *dest)
  798. {
  799.   char c;
  800.   register int i;
  801.  
  802.   switch(c = *((*strptr)++))
  803.     {
  804.     case '\\':
  805.  
  806.       switch(c = tolower((int) *((*strptr)++)))
  807.         {
  808.         case '\n':
  809.           return(0);
  810.         case 'b':
  811.           *dest = '\b';
  812.           break;
  813.         case 'c':
  814.           *dest = '\233';
  815.           break;
  816.         case 'e':
  817.           *dest = '\033';
  818.           break;
  819.         case 'f':
  820.           *dest = '\f';
  821.           break;
  822.         case 'g':
  823.           *dest = '\007';
  824.           break;
  825.         case 'n':
  826.           *dest = '\n';
  827.           break;
  828.         case 'r':
  829.           *dest = '\r';
  830.           break;
  831.         case 't':
  832.           *dest = '\t';
  833.           break;
  834.         case 'v':
  835.           *dest = '\013';
  836.           break;
  837.         case 'x':
  838.           *dest = gethex((int) **strptr);
  839.           (*strptr)++;
  840.           if (((c = **strptr) >= '0'  &&  c <= '9')  ||
  841.               (c >= 'a'  &&  c <= 'f')  ||  (c >= 'A'  &&  c <= 'F'))
  842.           { *dest = (*dest << 4) + gethex((int) c);
  843.             (*strptr)++;
  844.           }
  845.           break;
  846.         case '0':
  847.         case '1':
  848.         case '2':
  849.         case '3':
  850.         case '4':
  851.         case '5':
  852.         case '6':
  853.         case '7':
  854.  
  855.           *dest = getoctal((int)c);
  856.  
  857.           for(i = 0;  i < 2;  i++)
  858.             {
  859.             if((c = **strptr) >= '0'  &&  c <= '7')
  860.               {
  861.               *dest = (*dest << 3) + getoctal((int) c);
  862.               (*strptr)++;
  863.               }
  864.             }
  865.           break;
  866.         case ')':
  867.         case '\\':
  868.           *(dest++) = '\\';
  869.           *dest = c;
  870.           return(2);
  871.         default:
  872.           *dest = c;
  873.       }
  874.       break;
  875.  
  876.     default:
  877.       *dest = c;
  878.   }
  879.   return(1);
  880. }
  881. //|
  882. /// FUNC: ScanCDFile
  883.  
  884. /*
  885.     This scans the catalog description file.
  886.  
  887.     Inputs: cdfile  - name of the catalog description file
  888.  
  889.     Result: TRUE, if successful, FALSE otherwise
  890. */
  891. int ScanCDFile(char *cdfile)
  892. {
  893.   FILE *fp;
  894.   struct CDLine *cdline, **cdptr = &FirstCDLine;
  895.   struct CatString *cs, **csptr = &FirstCatString;
  896.   char *line, *newline;
  897.   char *ptr;
  898.   int NextID = 0, len;
  899.   int Result = TRUE;
  900.  
  901.   ScanFile = cdfile;
  902.   ScanLine = 0;
  903.  
  904.   if(!(fp = fopen(cdfile, "r")))
  905.     {
  906.     ShowError(msgNoCatalogDescription, cdfile);
  907.     }
  908.  
  909.   if(!NoBufferedIO)
  910.     setvbuf(fp, NULL, _IOFBF, buffer_size);
  911.  
  912.   /*
  913.       Get the basename
  914.   */
  915.   if ((ptr = strchr(cdfile, ':')))
  916.   { cdfile = ptr+1;
  917.   }
  918.   if ((ptr = strrchr(cdfile, '/')))
  919.   { cdfile = ptr+1;
  920.   }
  921.   if ((ptr = strrchr(cdfile, '.')))
  922.   { len = ptr-cdfile;
  923.   }
  924.   else
  925.   { len = strlen(cdfile);
  926.   }
  927.   if (!(BaseName = malloc(len+1)))
  928.   { MemError();
  929.   }
  930.   strncpy(BaseName, cdfile, len);
  931.   BaseName[len] = '\0';
  932.  
  933.   while(!feof(fp)  &&  (line = newline = ReadLine(fp, TRUE)))
  934.   {
  935.     if(!(cdline = malloc(sizeof(*cdline))))
  936.       {
  937.       MemError();
  938.       }
  939.  
  940.     *cdptr = cdline;
  941.     cdptr = &cdline->Next;
  942.     cdline->Next = NULL;
  943.     cdline->Line = line = AllocString(newline);
  944.     free(newline);
  945.  
  946.     if (*line == ';')
  947.       {
  948.       continue;
  949.       }
  950.  
  951.     if(*line == '#')
  952.       {
  953.       int CheckExtra = TRUE;
  954.  
  955.       if (strnicmp(line+1, "language", 8) == 0)
  956.         {
  957.         char *ptr;
  958.  
  959.         line += 9;
  960.         OverSpace(&line);
  961.         Language = AllocString(line);
  962.  
  963.         if(LANGToLower)
  964.            {
  965.            for (ptr = Language;  *ptr;  ptr++)
  966.              {
  967.              *ptr = tolower((int) *ptr);
  968.              }
  969.            CheckExtra = FALSE;
  970.            }
  971.  
  972.         }
  973.       else
  974.         if(strnicmp(line+1, "version", 7) == 0)
  975.           {
  976.           CatVersion = strtol(line+8, &line, 0);
  977.           }
  978.         else
  979.           {
  980.           if(strnicmp(line+1, "basename", 8) == 0)
  981.            {
  982.            line += 9;
  983.            OverSpace(&line);
  984.            free(BaseName);
  985.            BaseName = AllocString(line);
  986.            CheckExtra = FALSE;
  987.            }
  988.           else
  989.            {
  990.            ShowWarn(msgUnknownCDCommand);
  991.            Result = FALSE;
  992.            CheckExtra = FALSE;
  993.            }
  994.          }
  995.  
  996.       if(CheckExtra)
  997.         {
  998.         OverSpace(&line);
  999.           if(*line)
  1000.             {
  1001.             ShowWarn(msgExtraCharacters);
  1002.             Result = FALSE;
  1003.             }
  1004.         }
  1005.       }
  1006.     else
  1007.       {
  1008.       char *idstr;
  1009.  
  1010.       if(*line == ' '  ||  *line == '\t')
  1011.         {
  1012.         ShowWarn(msgUnexpectedBlanks);
  1013.         Result = FALSE;
  1014.         OverSpace(&line);
  1015.         }
  1016.  
  1017.       idstr = line;
  1018.       while ((*line >= 'a'  &&  *line <= 'z')  ||
  1019.              (*line >= 'A'  &&  *line <= 'Z')  ||
  1020.              (*line >= '0'  &&  *line <= '9')  ||
  1021.              *line == '_')
  1022.         {
  1023.         ++line;
  1024.         }
  1025.  
  1026.       if(idstr == line)
  1027.         {
  1028.         ShowWarn(msgNoIdentifier);
  1029.         Result = FALSE;
  1030.         }
  1031.       else
  1032.         {
  1033.         int found;
  1034.  
  1035.         if(!(cs = malloc(sizeof(*cs))))
  1036.           {
  1037.           MemError();
  1038.           }
  1039.  
  1040.         do
  1041.           {
  1042.           struct CatString *scs;
  1043.  
  1044.           found = TRUE;
  1045.           for(scs = FirstCatString;  scs != NULL;  scs = scs->Next)
  1046.             {
  1047.             if(scs->ID == NextID)
  1048.               {
  1049.               found = FALSE;
  1050.               ++NextID;
  1051.               break;
  1052.               }
  1053.             }
  1054.           }
  1055.         while(!found);
  1056.  
  1057.         cs->Next = NULL;
  1058.         cs->ID = NextID;
  1059.         cs->MinLen = 0;
  1060.         cs->MaxLen = -1;
  1061.         cs->CD_Str = "";
  1062.         cs->CT_Str = NULL;
  1063.         cs->NotInCT= TRUE;
  1064.  
  1065.         if(!(cs->ID_Str = malloc((line-idstr)+1)))
  1066.           {
  1067.           MemError();
  1068.           }
  1069.         strncpy(cs->ID_Str, idstr, line-idstr);
  1070.         cs->ID_Str[line-idstr] = '\0';
  1071.  
  1072.         OverSpace(&line);
  1073.  
  1074.         if(*line != '(')
  1075.           {
  1076.           ShowWarn(msgNoLeadingBracket);
  1077.           Result = FALSE;
  1078.           }
  1079.         else
  1080.           {
  1081.           char *oldstr;
  1082.           struct CatString *scs;
  1083.           char bytes[10];
  1084.           int bytesread, reallen;
  1085.  
  1086.           ++line;
  1087.           OverSpace(&line);
  1088.           if(*line != '/')
  1089.             {
  1090.             if(*line == '+')
  1091.               {
  1092.               NextID = cs->ID = NextID + strtol(line, &line, 0);
  1093.               }
  1094.             else
  1095.               {
  1096.               cs->ID = NextID = strtol(line, &line, 0);
  1097.               }
  1098.  
  1099.             OverSpace(&line);
  1100.             }
  1101.  
  1102.           for(scs = FirstCatString;  scs != NULL;  scs = scs->Next)
  1103.           { if (scs->ID == cs->ID)
  1104.             { ShowWarn(msgDoubleID);
  1105.               Result = FALSE;
  1106.             }
  1107.             if (strcmp(cs->ID_Str, scs->ID_Str)  ==  0)
  1108.             { ShowWarn(msgDoubleIdentifier);
  1109.               Result = FALSE;
  1110.             }
  1111.           }
  1112.  
  1113.           if (*line != '/')
  1114.           { ShowWarn(msgNoMinLen);
  1115.             Result = FALSE;
  1116.           }
  1117.           else
  1118.           { ++line;
  1119.             OverSpace(&line);
  1120.             if (*line != '/')
  1121.             { cs->MinLen = strtol(line, &line, 0);
  1122.               OverSpace(&line);
  1123.             }
  1124.             if (*line != '/')
  1125.             { ShowWarn(msgNoMaxLen);
  1126.               Result = FALSE;
  1127.             }
  1128.             else
  1129.             { ++line;
  1130.               OverSpace(&line);
  1131.               if (*line != ')')
  1132.               { cs->MaxLen = strtol(line, &line, 0);
  1133.                 OverSpace(&line);
  1134.               }
  1135.               if (*line != ')')
  1136.               { ShowWarn(msgNoTrailingBracket);
  1137.                 Result = FALSE;
  1138.               }
  1139.               else
  1140.               { ++line;
  1141.                 OverSpace(&line);
  1142.                 if (*line)
  1143.                 { ShowWarn(msgExtraCharacters);
  1144.                 }
  1145.               }
  1146.             }
  1147.           }
  1148.         if (!(newline = ReadLine(fp, FALSE)))
  1149.         { ShowWarn(msgNoString);
  1150.           Result = FALSE;
  1151.           cs->CD_Str = "";
  1152.         }
  1153.         else
  1154.         { cs->CD_Str = AllocString(newline);
  1155.           free(newline);
  1156.         }
  1157.  
  1158.         /*
  1159.             Get stringlen
  1160.         */
  1161.         oldstr = cs->CD_Str;
  1162.         reallen = 0;
  1163.         while (*oldstr)
  1164.         { bytesread = ReadChar(&oldstr, bytes);
  1165.           if (bytesread == 2)
  1166.           { bytesread--;
  1167.           }
  1168.           reallen += bytesread;
  1169.         }
  1170.  
  1171.         if (cs->MinLen > 0  &&  reallen < cs->MinLen)
  1172.         { ShowWarn(msgShortString);
  1173.         }
  1174.         if (cs->MaxLen > 0  &&  reallen > cs->MaxLen)
  1175.         { ShowWarn(msgLongString);
  1176.         }
  1177.  
  1178.         cs->Nr = NumStrings;
  1179.  
  1180.         *csptr = cs;
  1181.         csptr = &cs->Next;
  1182.         ++NumStrings;
  1183.         }
  1184.       }
  1185.     }
  1186.   }
  1187.   fclose(fp);
  1188.   return(Result);
  1189. }
  1190. //|
  1191. /// FUNC: ScanCTFile
  1192.  
  1193. /*
  1194.     This scans a catalog translation file.
  1195.  
  1196.     Inputs: ctfile      - name of the translation file to scan.
  1197.  
  1198.     Result: TRUE, if successful, FALSE otherwise.
  1199. */
  1200. int ScanCTFile(char *ctfile)
  1201. {
  1202.   FILE *fp;
  1203.   char *newline, *line, *idstr, *newidstr, *newstr;
  1204.   struct CatString *cs=NULL;
  1205.   int Result = TRUE;
  1206.  
  1207.   ScanFile = ctfile;
  1208.   ScanLine = 0;
  1209.  
  1210.   if (!(fp = fopen(ctfile, "r")))
  1211.     {
  1212.     ShowError(msgNoCatalogTranslation, ctfile);
  1213.     }
  1214.  
  1215.   if(!NoBufferedIO)
  1216.     setvbuf(fp, NULL, _IOFBF, buffer_size);
  1217.  
  1218.  
  1219.   while (!feof(fp)  &&  (line = newline = ReadLine(fp, TRUE)))
  1220.     {
  1221.     switch(*line)
  1222.       {
  1223.       case ';':
  1224.         if( CopyNEWs == TRUE )
  1225.            {
  1226.            if(strnicmp( line, Old_Msg_New, strlen(Old_Msg_New) ) == 0)
  1227.              {
  1228.              cs->NotInCT = TRUE;
  1229.              }
  1230.            }
  1231.       break;
  1232.  
  1233.       case '#':
  1234. ///       looking for command;
  1235.         if(*(++line) != '#')
  1236.           {
  1237.           ShowWarn(msgNoCTCommand);
  1238.           }
  1239.         ++line;
  1240.         OverSpace(&line);
  1241.         if (strnicmp(line, "version", 7) == 0)
  1242.         { if (CatVersionString || CatRcsId || CatName)
  1243.           { ShowWarn(msgDoubleCTVersion);
  1244.           }
  1245.           line += 7;
  1246.           OverSpace(&line);
  1247.           CatVersionString = AllocString(line);
  1248.         }
  1249.         else if (strnicmp(line, "codeset", 7) == 0)
  1250.         { line += 7;
  1251.           CodeSet = strtol(line, &line, 0);
  1252.           OverSpace(&line);
  1253.           if (*line)
  1254.           { ShowWarn(msgExtraCharacters);
  1255.           }
  1256.         }
  1257.         else if (strnicmp(line, "language", 8) == 0)
  1258.         { char *ptr;
  1259.  
  1260.           if (CatLanguage)
  1261.           { ShowWarn(msgDoubleCTLanguage);
  1262.           }
  1263.           line += 8;
  1264.           OverSpace(&line);
  1265.           CatLanguage = AddCatalogChunk("LANG", line);
  1266.  
  1267.           if(LANGToLower)
  1268.             for (ptr = CatLanguage;  *ptr;  ptr++)
  1269.               *ptr = tolower((int) *ptr);
  1270.         }
  1271.         else if (strnicmp(line, "chunk", 5) == 0)
  1272.         { char *ID;
  1273.  
  1274.           line += 5;
  1275.           OverSpace(&line);
  1276.           ID = line;
  1277.           line += sizeof(ULONG);
  1278.           OverSpace(&line);
  1279.  
  1280.           AddCatalogChunk(ID, AllocString(line));
  1281.         }
  1282.         else if (strnicmp(line, "rcsid", 5) == 0)
  1283.         { if (CatVersionString || CatRcsId)
  1284.           { ShowWarn(msgDoubleCTVersion);
  1285.           }
  1286.           line += 5;
  1287.           OverSpace(&line);
  1288.           CatRcsId = AllocString(line);
  1289.         }
  1290.         else if (strnicmp(line, "name", 5) == 0)
  1291.         { if (CatVersionString || CatName)
  1292.           { ShowWarn(msgDoubleCTVersion);
  1293.           }
  1294.           line += 4;
  1295.           OverSpace(&line);
  1296.           CatName = AllocString(line);
  1297.         }
  1298.         else if (strnicmp(line+1, "lengthbytes", 11) == 0)
  1299.         { line += 12;
  1300.           if ((LengthBytes = strtol(line, &line, 0))
  1301.                            > sizeof(long))
  1302.           { ShowWarn(msgNoLengthBytes, sizeof(long));
  1303.             LengthBytes = sizeof(long);
  1304.           }
  1305.         }
  1306.         else
  1307.         {
  1308.         ShowWarn(msgUnknownCTCommand);
  1309.         }
  1310. //|
  1311.         break;
  1312.  
  1313.       default:
  1314.         if(*line == ' '  ||  *line == '\t')
  1315.           {
  1316.           ShowWarn( msgUnexpectedBlanks );
  1317.           OverSpace( &line );
  1318.           }
  1319.         idstr = line;
  1320.  
  1321.         while ((*line >= 'a'  &&  *line <= 'z')  ||
  1322.                (*line >= 'A'  &&  *line <= 'Z')  ||
  1323.                (*line >= '0'  &&  *line <= '9')  ||
  1324.                *line == '_')
  1325.         { ++line;
  1326.         }
  1327.         if (idstr == line)
  1328.           {
  1329.           ShowWarn(msgNoIdentifier);
  1330.           break;
  1331.           }
  1332.  
  1333.         if(!(newidstr = malloc(line-idstr+1)))
  1334.           {
  1335.           MemError();
  1336.           }
  1337.  
  1338.         strncpy(newidstr, idstr, line-idstr);
  1339.         newidstr[line-idstr] = '\0';
  1340.         OverSpace(&line);
  1341.  
  1342.         if(*line)
  1343.           {
  1344.           ShowWarn(msgExtraCharacters);
  1345.           }
  1346.  
  1347.         if((newstr = ReadLine(fp, FALSE)))
  1348.           {
  1349.           for(cs = FirstCatString;  cs != NULL;  cs = cs->Next)
  1350.             {
  1351.             if(strcmp(cs->ID_Str, newidstr) == 0)
  1352.               {
  1353.               break;
  1354.               }
  1355.             }
  1356.           if(cs == NULL)
  1357.             {
  1358.             ShowWarn(msgUnknownIdentifier, newidstr);
  1359.             }
  1360.           else
  1361.             {
  1362.             char *oldstr;
  1363.             char bytes[10];
  1364.             int bytesread, reallen;
  1365.  
  1366.             if(cs->CT_Str)
  1367.               {
  1368.               ShowWarn(msgDoubleIdentifier);
  1369.               Result = FALSE;
  1370.               free(cs->CT_Str);
  1371.               }
  1372.             cs->CT_Str = AllocString(newstr);
  1373.             cs->NotInCT = FALSE;
  1374.  
  1375.             /*
  1376.                 Get stringlen
  1377.             */
  1378.             oldstr = cs->CT_Str;
  1379.             reallen = 0;
  1380.             while(*oldstr)
  1381.               {
  1382.               bytesread = ReadChar(&oldstr, bytes);
  1383.               if(bytesread == 2)
  1384.                 {
  1385.                 bytesread--;
  1386.                 }
  1387.               reallen += bytesread;
  1388.               }
  1389.  
  1390.             if(cs->MinLen > 0  &&  reallen < cs->MinLen)
  1391.               {
  1392.               ShowWarn(msgShortString);
  1393.               }
  1394.             if(cs->MaxLen > 0  &&  reallen > cs->MaxLen)
  1395.               {
  1396.               ShowWarn(msgLongString);
  1397.               }
  1398.  
  1399.  
  1400.             // checking for trailing ellipsis...
  1401.  
  1402.             if( reallen >= 3 )
  1403.                {
  1404.                long cd_len = strlen( cs->CD_Str );
  1405.  
  1406.                if( cd_len >= 3 )
  1407.                    {
  1408.                    if( strcmp( &cs->CD_Str[ cd_len - 2 ], "..." ) == 0 )
  1409.                        if( strcmp( &cs->CT_Str[ reallen - 2 ], "..." ) != 0 )
  1410.                          {
  1411. //                         printf("ORG: '%s'\nNEW: '%s'\n", cs->CD_Str, cs->CT_Str);
  1412.                          ShowWarn(msgTrailingEllipsis);
  1413.                          }
  1414.                    }
  1415.                }
  1416.  
  1417.  
  1418.             // checking for trailing spaces
  1419.  
  1420.             if( reallen >= 1 )
  1421.                {
  1422.                long cd_len = strlen( cs->CD_Str );
  1423.  
  1424.                if( cd_len >= 1 )
  1425.                    {
  1426.                    if( strcmp( &cs->CD_Str[ cd_len - 1 ], " " ) == 0 )
  1427.                        if( strcmp( &cs->CT_Str[ reallen - 1 ], " " ) != 0 )
  1428.                          ShowWarn(msgTrailingSpaces);
  1429.                    }
  1430.                }
  1431.  
  1432.  
  1433.             }
  1434.           free(newstr);
  1435.           }
  1436.         else
  1437.           {
  1438.           ShowWarn(msgNoString);
  1439.           if(cs)
  1440.               cs->CT_Str = "";
  1441.           }
  1442.         free(newidstr);
  1443.     }
  1444.     free(newline);
  1445.   }
  1446.  
  1447.   fclose(fp);
  1448.  
  1449.   if (WarnCTGaps)
  1450.   { for (cs = FirstCatString;  cs != NULL;  cs = cs->Next)
  1451.     { if (cs->CT_Str == NULL)
  1452.       { ShowWarn(msgCTGap, cs->ID_Str);
  1453.       }
  1454.     }
  1455.   }
  1456.  
  1457.   if(Result)
  1458.     CT_Scanned = TRUE;
  1459.  
  1460.   return(Result);
  1461. }
  1462. //|
  1463. /// FUNC: CatPuts
  1464.  
  1465.  
  1466. /*
  1467.     CatPuts prints a string to a catalog. (The string is preceded by a
  1468.     long integer containing its length and probably padded up to word
  1469.     boundary or longword boundary, depending on the argument padbytes.)
  1470.     The arguments countnul should be TRUE if the NUL byte at the end of
  1471.     the string should be counted.
  1472. */
  1473. int CatPuts(FILE *fp, char *str, int padbytes, int countnul)
  1474. {
  1475.   unsigned long reallen, virtuallen, chunklen, swapped_long;
  1476.   int bytesread;
  1477.   char *oldstr;
  1478.   char bytes[10];
  1479.  
  1480.   /*      Get Length of string.
  1481.   */
  1482.  
  1483.   oldstr = str;
  1484.   reallen = 0;
  1485.  
  1486.   while(*oldstr)
  1487.     {
  1488.     bytesread = ReadChar(&oldstr, bytes);
  1489.     if(bytesread == 2)
  1490.       {
  1491.       bytesread--;
  1492.       }
  1493.     reallen += bytesread;
  1494.     }
  1495.  
  1496.   virtuallen = chunklen = reallen + LengthBytes;
  1497.   if(countnul || chunklen % padbytes == 0)
  1498.     {
  1499.     virtuallen++;
  1500.     }
  1501.  
  1502.   swapped_long = SwapLong( virtuallen );
  1503.  
  1504.   fwrite(&swapped_long, sizeof(virtuallen), 1, fp);
  1505.   if(LengthBytes)
  1506.     {
  1507.     fwrite(((char *) &reallen)+sizeof(reallen)-LengthBytes, LengthBytes, 1, fp);
  1508.     }
  1509.  
  1510.   while(*str)
  1511.     {
  1512.     bytesread = ReadChar(&str, bytes);
  1513.     if(bytesread)
  1514.       {
  1515.       fwrite(bytes+bytesread-1, 1, 1, fp);
  1516.       }
  1517.     }
  1518.  
  1519.   do
  1520.     {
  1521.     putc('\0', fp);
  1522.     }
  1523.   while(++chunklen % padbytes);
  1524.  
  1525.   return((int) chunklen+4);
  1526. }
  1527. //|
  1528. /// FUNC: PutCatalogChunk
  1529.  
  1530. /*
  1531.     This puts a string chunk into the catalog
  1532. */
  1533. int PutCatalogChunk(FILE *fp, struct CatalogChunk *cc)
  1534. {
  1535.   fwrite(&cc->ID, sizeof(cc->ID), 1, fp);
  1536.   return(4 + CatPuts(fp, cc->ChunkStr, 2, TRUE));
  1537. }
  1538. //|
  1539. /// FUNC: CalcRealLength
  1540. /*
  1541.     This function measures the real (binary) length of source
  1542.     string. It correctly process 'slash chars' (\n, \000 etc),
  1543.     and gives the real length such source string have.
  1544.  
  1545.     Inputs: source - pointer to null terminated source string
  1546.  
  1547.     Result: real length
  1548. */
  1549.  
  1550. int CalcRealLength(char *source)
  1551. {
  1552. int  count = 0;
  1553. char *src = source;
  1554. char bytes[10];
  1555.  
  1556.   while(*src)
  1557.     {
  1558.     count += ReadChar(&src, bytes);
  1559.     }
  1560.  
  1561. //  printf("%ld: '%s'\n", count, source);
  1562.  
  1563.   return(count);
  1564.  
  1565. }
  1566. //|
  1567.  
  1568. /// FUNC: CreateCatalog
  1569.  
  1570. /*
  1571.     This creates a catalog.
  1572. */
  1573. void CreateCat(char *CatFile)
  1574. {
  1575.   FILE *fp;
  1576.   int CatLen, HeadLen;
  1577.   struct CatString *cs;
  1578.   struct CatalogChunk *cc;
  1579.   int i;
  1580.  
  1581.   if(!CatVersionString && !CatRcsId)
  1582.     {
  1583.     ShowError(msgNoCTVersion);
  1584.     }
  1585.  
  1586.   if(!CatLanguage)
  1587.     {
  1588.     ShowError(msgNoCTLanguage);
  1589.     }
  1590.  
  1591.   if(strlen(CatLanguage) == 0)
  1592.     {
  1593.     ShowError(msgNoCTLanguage);
  1594.     }
  1595.  
  1596.   if(!(fp = fopen(CatFile, "w")))
  1597.     {
  1598.     ShowError(msgNoCatalog, CatFile);
  1599.     }
  1600.  
  1601.   if(!NoBufferedIO)
  1602.     setvbuf(fp, NULL, _IOFBF, buffer_size);
  1603.  
  1604.  
  1605.   fputs("FORM0000CTLG", fp);
  1606.   CatLen = 4;
  1607.  
  1608.   if(CatVersionString)
  1609.     {
  1610.     struct CatalogChunk cc;
  1611.     char *verStr = NULL;
  1612.  
  1613.     cc.ID = MAKE_ID('F','V','E','R');
  1614.  
  1615.     if( strstr(CatVersionString, "$TODAY") )
  1616.        {
  1617.  
  1618.        if(verStr = malloc(strlen(CatVersionString)+128))
  1619.            {
  1620.            char *found = strstr(CatVersionString, "$TODAY");
  1621.            char dateStr[10];
  1622.  
  1623.            long tim;
  1624.            struct tm *t;
  1625.  
  1626.            time(&tim);
  1627.            t = localtime(&tim);
  1628.  
  1629.            *found = 0;
  1630.            strftime(dateStr, sizeof(dateStr), "%d.%m.%y", t);
  1631.  
  1632.            sprintf(verStr, "%s%s%s", CatVersionString, dateStr, found+strlen("$TODAY"));
  1633.            cc.ChunkStr = verStr;
  1634.            }
  1635.        else
  1636.           MemError();
  1637.        }
  1638.     else
  1639.        {
  1640.        cc.ChunkStr = CatVersionString;
  1641.        }
  1642.  
  1643.     cc.ID = SwapLong( cc.ID );
  1644.     CatLen += PutCatalogChunk(fp, &cc);
  1645.  
  1646.     if( verStr )
  1647.        free(verStr);
  1648.     }
  1649.   else
  1650.     {
  1651.     struct CatalogChunk cc;
  1652.     char* verStr;
  1653.     int year = 0, month = 0, day = 0;
  1654.     int version = 0, revision = 0;
  1655.     char* name = NULL;
  1656.     char* ptr;
  1657.  
  1658.     if(!CatRcsId)
  1659.       {
  1660.       ShowError(msgNoCTVersion);
  1661.       }
  1662.     else
  1663.       {
  1664.       if(!(ptr = strstr(CatRcsId, "$Date:"))
  1665.           || sscanf(ptr+6, " %d/%d/%d", &year, &month, &day) != 3
  1666.           || !(ptr = strstr(CatRcsId, "$Revision:"))
  1667.           || sscanf(ptr+10, " %d.%d", &version, &revision) != 2)
  1668.       {
  1669.       ShowError(msgWrongRcsId);
  1670.       }
  1671.       if ((ptr = strstr(CatRcsId, "$Id:")))
  1672.       { int len = 0;
  1673.         char* found;
  1674.  
  1675.         ptr += 4;
  1676.         OverSpace(&ptr);
  1677.         found = ptr;
  1678.  
  1679.         while(*ptr  &&  *ptr != '$'  &&  *ptr != ' '  &&  *ptr != '\t')
  1680.           {
  1681.           ++len;
  1682.           ++ptr;
  1683.           }
  1684.         if(!(name = malloc(len+1)))
  1685.           {
  1686.           MemError();
  1687.          }
  1688.         strncpy(name, found, len);
  1689.         name[len] = '\0';
  1690.       }
  1691.     }
  1692.     if (CatName)
  1693.     { name = CatName;
  1694.     }
  1695.     else if (!name)
  1696.       {
  1697.       ShowError(msgNoCTVersion);
  1698.       name = "";
  1699.       }
  1700.     if (!(verStr = malloc(strlen(name) + 256)))
  1701.       {
  1702.       MemError();
  1703.       }
  1704.  
  1705.     sprintf(verStr, "$V");
  1706.     sprintf(verStr, "ER: %s %ld.%ld (%ld.%ld.%ld)", name, version, revision, day, month, year);
  1707.  
  1708.     cc.ID = MAKE_ID('F','V','E','R');
  1709.     cc.ID = SwapLong( cc.ID );
  1710.     cc.ChunkStr = verStr;
  1711.     CatLen += PutCatalogChunk(fp, &cc);
  1712.   }
  1713.  
  1714.  
  1715.   for (cc = FirstChunk;  cc != NULL;  cc = cc->Next)
  1716.     {
  1717.     CatLen += PutCatalogChunk(fp, cc);
  1718.     }
  1719.  
  1720.   i = 32;
  1721.   fputs("CSET", fp);
  1722.  
  1723.   {
  1724.   int i_tmp = SwapLong( i );
  1725.  
  1726.   fwrite(&i_tmp, sizeof(i_tmp), 1, fp);
  1727.   }
  1728.  
  1729.   while(i-- > 0)
  1730.     {
  1731.     putc('\0', fp);
  1732.     }
  1733.  
  1734.   CatLen += 48;
  1735.   fprintf(fp, "STRS0000");
  1736.   HeadLen = CatLen;
  1737.  
  1738.  
  1739.   for(cs = FirstCatString;  cs != NULL;  cs = cs->Next)
  1740.     {
  1741.     int FillUsed = FALSE;
  1742.     int tmp_ID = SwapLong( cs->ID );
  1743.  
  1744.     if(Fill)
  1745.       {
  1746.  
  1747.       if(cs->CT_Str)
  1748.         {
  1749.         if(strlen(cs->CT_Str) == 0)
  1750.           {
  1751.           fwrite(&tmp_ID, sizeof(tmp_ID), 1, fp);
  1752.           CatLen += 4 + CatPuts(fp, cs->CD_Str, 4, FALSE);
  1753.           FillUsed = TRUE;
  1754.           }
  1755.         }
  1756.       else
  1757.         {
  1758.         fwrite(&tmp_ID, sizeof(cs->ID), 1, fp);
  1759.         CatLen += 4 + CatPuts(fp, cs->CD_Str, 4, FALSE);
  1760.         FillUsed = TRUE;
  1761.         }
  1762.       }
  1763.  
  1764.     if((!FillUsed) && cs->CT_Str  &&  (NoOptim ? TRUE : strcmp(cs->CT_Str, cs->CD_Str)))
  1765.       {
  1766.       fwrite(&tmp_ID, sizeof( tmp_ID ), 1, fp);
  1767.       CatLen += 4 + CatPuts(fp, cs->CT_Str, 4, FALSE);
  1768.       }
  1769.     }
  1770.  
  1771.  
  1772.   {
  1773.   int tmp_Len;
  1774.  
  1775.   fseek(fp, 4, SEEK_SET);
  1776.  
  1777.   tmp_Len = SwapLong( CatLen );
  1778.   fwrite(&tmp_Len, sizeof(tmp_Len), 1, fp);
  1779.   fseek(fp, HeadLen-4, SEEK_CUR);
  1780.  
  1781.   CatLen -= HeadLen;
  1782.   tmp_Len = SwapLong( CatLen );
  1783.   fwrite(&tmp_Len, sizeof(CatLen), 1, fp);
  1784.   }
  1785.  
  1786.   fclose(fp);
  1787.  
  1788.   Expunge();
  1789.  
  1790. }
  1791. //|
  1792. /// FUNC: CreateCTFile
  1793.  
  1794. /*
  1795.     This creates a new catalog translation file.
  1796. */
  1797. void CreateCTFile(char *NewCTFile)
  1798. {
  1799.   FILE   *fp;
  1800.   struct CDLine *cd;
  1801.   struct CatString *cs;
  1802.   struct CatalogChunk *cc;
  1803.   char   *line;
  1804.  
  1805.   if(!CatVersionString && !CatRcsId)
  1806.     {
  1807.     ScanLine = 1;
  1808.     ShowWarn(msgNoCTVersion);
  1809.     }
  1810.  
  1811.   if(!(fp = fopen(NewCTFile, "w")))
  1812.     {
  1813.     ShowError(msgNoNewCTFile);
  1814.     }
  1815.  
  1816.  
  1817.   if(!NoBufferedIO)
  1818.     setvbuf(fp, NULL, _IOFBF, buffer_size);
  1819.  
  1820.  
  1821.   if(CatRcsId)
  1822.     {
  1823.     fprintf(fp, "## rcsid %s\n",
  1824.           CatRcsId ? CatRcsId : "");
  1825.     if(CatName)
  1826.        fprintf(fp, "## name %s\n", CatName);
  1827.     }
  1828.   else
  1829.     {
  1830.     if(CatVersionString)
  1831.       fprintf(fp, "## version %s\n", CatVersionString);
  1832.     else
  1833.       {
  1834.       fprintf(fp, "## version $V");
  1835.       fprintf(fp, "%c", 50+19);  // E
  1836.       fprintf(fp, "R: XX.catalog XX.XX ($TODAY)\n");
  1837.       }
  1838.     }
  1839.  
  1840.  
  1841.   {
  1842.   char *lang = NULL;
  1843.  
  1844.   if(CatLanguage == NULL)
  1845.     if(lang = getenv("ENV:language"))
  1846.       {
  1847.       register int i;
  1848.  
  1849.       for(i=0;i<strlen(lang); i++)
  1850.         if(lang[i] == '\n')
  1851.           {
  1852.           lang[i] = 0;
  1853.           break;
  1854.           }
  1855.  
  1856.       CatLanguage = lang;
  1857.       }
  1858.  
  1859.   fprintf(fp, "## language %s\n## codeset %d\n;\n",
  1860.        CatLanguage ? CatLanguage : "X", CodeSet);
  1861.  
  1862.   if(lang)
  1863.     {
  1864.     free(lang);
  1865.     CatLanguage = NULL;
  1866.     }
  1867.   }
  1868.  
  1869.  
  1870.  
  1871.   for (cc = FirstChunk;  cc != NULL;  cc = cc->Next)
  1872.     {
  1873.     if (cc->ChunkStr != CatLanguage)
  1874.       {
  1875.       fprintf(fp, "## chunk ");
  1876.       fwrite((char *) &cc->ID, sizeof(cc->ID), 1, fp);
  1877.       fprintf(fp, " %s\n", cc->ChunkStr);
  1878.       }
  1879.     }
  1880.  
  1881.   for(cd = FirstCDLine, cs = FirstCatString;
  1882.       cd != NULL;
  1883.       cd = cd->Next)
  1884.      {
  1885.      switch(*cd->Line)
  1886.        {
  1887.        case '#':
  1888.           break;
  1889.  
  1890.        case ';':
  1891.           fprintf(fp, "%s\n", cd->Line);
  1892.           break;
  1893.  
  1894.        default:
  1895.           if(cs)
  1896.             {
  1897. /*
  1898.             fprintf(fp, "%s\n", cs->ID_Str);
  1899.             fprintf(fp, "%s\n", cs->CT_Str ? cs->CT_Str : "");
  1900.             putc(';', fp);
  1901.             putc(' ', fp);
  1902. */
  1903.             fprintf(fp, "%s\n%s\n;", cs->ID_Str, cs->CT_Str ? cs->CT_Str : "");
  1904.  
  1905.             if( !NoSpace )
  1906.                 putc(' ', fp);
  1907.  
  1908.  
  1909.  
  1910.             for (line = cs->CD_Str;  *line;  ++line)
  1911.               {
  1912.               putc((int) *line, fp);
  1913.               if(*line == '\n')
  1914.                 {
  1915.                 putc(';', fp);
  1916.                 if( !NoSpace )
  1917.                    putc(' ', fp);
  1918.                 }
  1919.               }
  1920.             putc('\n', fp);
  1921.  
  1922.             if(cs->NotInCT && CT_Scanned)
  1923.               fprintf(fp, ";\n; %s\n", Msg_New);
  1924.  
  1925.             cs = cs->Next;
  1926.             }
  1927.        }
  1928.      }
  1929.  
  1930.   fclose(fp);
  1931. }
  1932. //|
  1933.  
  1934. /// FUNC: InitCatStringOutput
  1935.  
  1936. /*
  1937.     InitCatStringOutput gets called before writing a catalog string as
  1938.     source.
  1939.  
  1940.     Inputs: fp   = file pointer to the output file
  1941.             type = one of   TYPE_C          create C strings
  1942.                             TYPE_ASSEMBLER  create Assembler strings
  1943.                             TYPE_OBERON     create Oberon strings
  1944.                             TYPE_E          create E strings
  1945.                             TYPE_NONE       create simple strings
  1946. */
  1947. int  OutputMode = OutputMode_None;
  1948. int  OutputType = TYPE_C;
  1949. FILE *OutputFile;
  1950. int  OutputLen;
  1951.  
  1952. void InitCatStringOutput(FILE *fp)
  1953. {
  1954.   OutputLen = 0;
  1955.   OutputFile = fp;
  1956.   OutputMode = OutputMode_None;
  1957.   switch(OutputType)
  1958.   { case TYPE_C:
  1959.     case TYPE_OBERON:
  1960.       putc('\"', fp);
  1961.       OutputMode = OutputMode_Ascii;
  1962.       break;
  1963.     case TYPE_E:
  1964.       putc('\'', fp);
  1965.     case TYPE_ASSEMBLER:
  1966.     case TYPE_NONE:
  1967.       break;
  1968.   }
  1969. }
  1970. //|
  1971. /// FUNC: SeparateCatStringOutput
  1972.  
  1973. /*
  1974.     SeparateCatStringOutput gets called to split a catalog into separate
  1975.     lines.
  1976. */
  1977. void SeparateCatStringOutput(void)
  1978. {
  1979.     switch(OutputType)
  1980.     { case TYPE_C:
  1981.         if (!LongStrings)
  1982.         { fputs("\"\\\n\t\"", OutputFile);
  1983.         }
  1984.         break;
  1985.       case TYPE_E:
  1986.         if (!LongStrings)
  1987.         { fputs("\' +\n\t\'", OutputFile);
  1988.         }
  1989.         break;
  1990.       case TYPE_OBERON:
  1991.         if (!LongStrings)
  1992.         { fputs("\"\n\t\"", OutputFile);
  1993.         }
  1994.         break;
  1995.       case TYPE_ASSEMBLER:
  1996.         if (!LongStrings)
  1997.         { if (OutputMode == OutputMode_Ascii)
  1998.           { putc('\'', OutputFile);
  1999.           }
  2000.           putc('\n', OutputFile);
  2001.           OutputMode = OutputMode_None;
  2002.         }
  2003.         break;
  2004.       case TYPE_NONE:
  2005.         break;
  2006.     }
  2007. }
  2008. //|
  2009. /// FUNC: WriteBinChar
  2010.  
  2011. /*
  2012.     WriteBinChar writes one binary character into the source file
  2013. */
  2014. void WriteBinChar(int c)
  2015. {
  2016.  
  2017.   switch(OutputType)
  2018.   { case TYPE_C:
  2019.     case TYPE_E:
  2020.     case TYPE_OBERON:
  2021.       switch(c)
  2022.       { case '\b':
  2023.           fputs("\\b", OutputFile);
  2024.           break;
  2025.         case '\n':
  2026.           fputs("\\n", OutputFile);
  2027.           break;
  2028.         case '\r':
  2029.           fputs("\\r", OutputFile);
  2030.           break;
  2031.         case '\t':
  2032.           fputs("\\t", OutputFile);
  2033.           break;
  2034.         case '\f':
  2035.           fputs("\\f", OutputFile);
  2036.           break;
  2037.         case '\0':
  2038.           fputs("\\000", OutputFile);
  2039.           break;
  2040.         default:
  2041.           if(OutputType == TYPE_E  &&  c == '\033')
  2042.             {
  2043.             fputs("\\e", OutputFile);
  2044.             }
  2045.           else
  2046.            {
  2047.            fprintf(OutputFile, "\\%c%c%c", ((c >> 6) & 3) + '0',
  2048.                     ((c >> 3) & 7) + '0', (c & 7) + '0');
  2049.            }
  2050.           break;
  2051.       }
  2052.       ++OutputLen;
  2053.       OutputMode = OutputMode_Bin;
  2054.       break;
  2055.     case TYPE_ASSEMBLER:
  2056.       switch(OutputMode)
  2057.       { case OutputMode_None:
  2058.           fprintf(OutputFile, "\tdc.b\t$%02x", c & 0xff);
  2059.           break;
  2060.         case OutputMode_Ascii:
  2061.           putc('\'', OutputFile);
  2062.         case OutputMode_Bin:
  2063.           fprintf(OutputFile, ",$%02x", c & 0xff);
  2064.           break;
  2065.       }
  2066.       ++OutputLen;
  2067.       OutputMode = OutputMode_Bin;
  2068.       break;
  2069.     case TYPE_NONE:
  2070.       ShowWarn(msgNoBinChars);
  2071.       break;
  2072.   }
  2073. }
  2074. //|
  2075. /// FUNC: WriteAsciiChar
  2076.  
  2077. /*
  2078.     WriteAsciiChar writes one ascii character into the source file.
  2079. */
  2080. void WriteAsciiChar(int c)
  2081. {
  2082.  
  2083.   switch(OutputType)
  2084.   { case TYPE_C:
  2085.     case TYPE_OBERON:
  2086.       switch(c)
  2087.       { case '\"':
  2088.           fputs("\\\"", OutputFile);
  2089.           break;
  2090.         default:
  2091.           putc(c, OutputFile);
  2092.           break;
  2093.       }
  2094.       ++OutputLen;
  2095.       OutputMode = OutputMode_Ascii;
  2096.       break;
  2097.     case TYPE_E:
  2098.       switch(c)
  2099.       { case '\'':
  2100.           fputs("''", OutputFile);
  2101.           break;
  2102.         default:
  2103.           putc(c, OutputFile);
  2104.           break;
  2105.       }
  2106.       ++OutputLen;
  2107.       OutputMode = OutputMode_Ascii;
  2108.       break;
  2109.     case TYPE_ASSEMBLER:
  2110.       if (c == '\'')
  2111.       { WriteBinChar(c);
  2112.       }
  2113.       else
  2114.       { switch (OutputMode)
  2115.         { case OutputMode_None:
  2116.             fprintf(OutputFile, "\tdc.b\t\'%c", c);
  2117.             break;
  2118.           case OutputMode_Ascii:
  2119.             putc(c, OutputFile);
  2120.             break;
  2121.           case OutputMode_Bin:
  2122.             fprintf(OutputFile, ",\'%c", c);
  2123.             break;
  2124.         }
  2125.         ++OutputLen;
  2126.         OutputMode = OutputMode_Ascii;
  2127.       }
  2128.       break;
  2129.     case TYPE_NONE:
  2130.       putc(c, OutputFile);
  2131.       break;
  2132.   }
  2133. }
  2134. //|
  2135. /// FUNC: TerminateCatStringOutput
  2136.  
  2137. /*
  2138.     TerminateCatStringOutput finishs the output of a catalog string.
  2139. */
  2140. void TerminateCatStringOutput(void)
  2141. {
  2142.   switch(OutputType)
  2143.   { case TYPE_C:
  2144.     case TYPE_OBERON:
  2145.       putc('\"', OutputFile);
  2146.       break;
  2147.     case TYPE_E:
  2148.       putc('\'', OutputFile);
  2149.       break;
  2150.     case TYPE_ASSEMBLER:
  2151.       switch(OutputMode)
  2152.       { case OutputMode_Ascii:
  2153.           putc('\'', OutputFile);
  2154.         case OutputMode_Bin:
  2155.           break;
  2156.         case OutputMode_None:
  2157.           break;
  2158.       }
  2159.     case TYPE_NONE:
  2160.       break;
  2161.   }
  2162. }
  2163. //|
  2164.  
  2165. /// FUNC: WriteString
  2166. /*
  2167.     This writes a sourcestring.
  2168. */
  2169. void WriteString(FILE *fpout, char *str, long Len)
  2170. {
  2171.   char bytes[10];
  2172.   int bytesread;
  2173.   int needseparate = FALSE;
  2174.  
  2175.   InitCatStringOutput(fpout);
  2176.   if (Len >= 0)
  2177.   { register int i;
  2178.  
  2179.     for(i = LengthBytes;  i >= 1;  i--)
  2180.     { WriteBinChar((int) ((char *) &Len)[sizeof(Len)-i]);
  2181.     }
  2182.   }
  2183.  
  2184.   while (*str)
  2185.   { bytesread = ReadChar(&str, bytes);
  2186.     if (bytesread)
  2187.     { unsigned char c;
  2188.  
  2189.       if (needseparate)
  2190.       { SeparateCatStringOutput();
  2191.         needseparate = FALSE;
  2192.       }
  2193.  
  2194.       c = bytes[bytesread-1];
  2195.       if ((c >= 0x20  &&  c < 0x7f)  ||  c >= 0xa0)
  2196.       { WriteAsciiChar((int) c);
  2197.       }
  2198.       else
  2199.       { WriteBinChar((int) c);
  2200.       }
  2201.     }
  2202.     else
  2203.     { needseparate = TRUE;
  2204.     }
  2205.   }
  2206.   TerminateCatStringOutput();
  2207. }
  2208. //|
  2209. /// FUNC: AllocFileName
  2210. /*
  2211.     This function creates a copy of a filename, removes an
  2212.     optional ending and pathname components, if desired.
  2213.  
  2214.     Inputs: filename - the filename to copy
  2215.             howto - a set of bits
  2216.                         bit 0: 1 = remove ending, 0 = leave it
  2217.                         bit 1: 1 = remove pathname, 0 = leave it
  2218.  
  2219.     Result: The copy of the filename
  2220. */
  2221. char *AllocFileName(char *filename, int howto)
  2222. {
  2223.   char *tempstr, *ptr;
  2224.  
  2225.   if (!(tempstr = strdup(filename)))
  2226.   { MemError();
  2227.     MyExit(10);
  2228.   }
  2229.  
  2230.   /*  Remove pathname components, if desired    */
  2231.   if (howto & 2)
  2232.   { if ((ptr = strchr(tempstr, ':')))
  2233.     { tempstr = ptr+1;
  2234.     }
  2235.     if ((ptr = strrchr(tempstr, '/')))
  2236.     { tempstr = ptr+1;
  2237.     }
  2238.   }
  2239.  
  2240.   /*  Remove ending, if desired.                */
  2241.   if (howto & 1)
  2242.   { if ((ptr = strrchr(tempstr, '.')))
  2243.     { *ptr = '\0';
  2244.     }
  2245.   }
  2246.  
  2247.   return(tempstr);
  2248. }
  2249. //|
  2250. /// FUNC: AddFileName
  2251. /*
  2252.     This function adds a pathname and a filename to a full
  2253.     filename.
  2254.  
  2255.     Inputs: pathname - the leading pathname
  2256.             filename - the filename
  2257.  
  2258.     Result: The new filename
  2259. */
  2260. char *AddFileName(char *pathname, char *filename)
  2261. {
  2262.   char *buffer;
  2263.   int size = strlen(pathname) + strlen(filename) + 2;
  2264.  
  2265.   if (!(buffer = malloc(size)))
  2266.   { MemError();
  2267.     MyExit(10);
  2268.   }
  2269.  
  2270. #if defined(__amigados)
  2271.   strcpy(buffer, pathname);
  2272.   AddPart((char *) buffer, (char *) filename, size);
  2273. #else
  2274.   sprintf(buffer, "%s/%s", pathname, filename);
  2275. #endif
  2276.  
  2277.   return(buffer);
  2278. }
  2279. //|
  2280.  
  2281. /// FUNC: CreateSourceFile
  2282.  
  2283. /*
  2284.     Finally the source creation.
  2285. */
  2286. void CreateSourceFile(char *SourceFile, char *TemplateFile, char *CDFile)
  2287. {
  2288.  
  2289.   FILE *fpin, *fpout;
  2290.   char *line;
  2291.   char *OrigTemplateFile = TemplateFile;
  2292.  
  2293.   ScanFile = SourceFile;
  2294.   ScanLine = 0;
  2295.  
  2296.   /*
  2297.     Open the source file. This may be found in various places
  2298.   */
  2299.   if(!(fpin = fopen(TemplateFile, "r")))
  2300.     {
  2301. #ifdef __amigados
  2302.     if(*prefs_sddir != 0)
  2303.       {
  2304.       TemplateFile = AddFileName(prefs_sddir, OrigTemplateFile);
  2305.       fpin = fopen(TemplateFile, "r");
  2306.       }
  2307. #endif
  2308.     }
  2309.  
  2310.   if(!fpin)
  2311.     {
  2312.     char *sddir;
  2313.  
  2314.     if((sddir = getenv(FLEXCAT_SDDIR)))
  2315.       {
  2316.       TemplateFile = AddFileName(sddir, OrigTemplateFile);
  2317.       fpin = fopen(TemplateFile, "r");
  2318.       }
  2319.     }
  2320.  
  2321.   if (!fpin)
  2322.   { TemplateFile = AddFileName(DEFAULT_FLEXCAT_SDDIR, OrigTemplateFile);
  2323.     fpin = fopen(TemplateFile, "r");
  2324.   }
  2325.  
  2326.   if (!fpin)
  2327.     {
  2328.       ShowError(msgNoSourceDescription, OrigTemplateFile);
  2329.       return;
  2330.     }
  2331.  
  2332.   if (!(fpout = fopen(SourceFile, "w")))
  2333.   {
  2334.     ShowError(msgNoSource, SourceFile);
  2335.     return;
  2336.   }
  2337.  
  2338.   if(!NoBufferedIO)
  2339.     setvbuf(fpin, NULL, _IOFBF, buffer_size);
  2340.   if(!NoBufferedIO)
  2341.     setvbuf(fpout, NULL, _IOFBF, buffer_size);
  2342.  
  2343.  
  2344.   while(!feof(fpin)  &&  (line = ReadLine(fpin, FALSE)))
  2345.   { struct CatString *cs;
  2346.     int NeedRepeat;
  2347.     char bytes[10];
  2348.     int bytesread;
  2349.  
  2350.     cs = FirstCatString;
  2351.     do
  2352.     { char *currentline = line;
  2353.       NeedRepeat = FALSE;
  2354.  
  2355.       if (*currentline == '#'  &&  *(++currentline) == '#')
  2356.       { ++currentline;
  2357.         OverSpace(¤tline);
  2358.  
  2359.         if(strnicmp( currentline, "rem", 3 ) == 0)
  2360.            {
  2361.            // we just skip this line
  2362.            continue;
  2363.            }
  2364.  
  2365.         if (strnicmp(currentline, "stringtype", 10) == 0)
  2366.         { currentline += 10;
  2367.           OverSpace(¤tline);
  2368.           if (strnicmp(currentline, "c", 1) == 0)
  2369.           { OutputType = TYPE_C;
  2370.             ++currentline;
  2371.           }
  2372.           else if (strnicmp(currentline, "assembler", 9) == 0)
  2373.           { OutputType = TYPE_ASSEMBLER;
  2374.             currentline += 9;
  2375.           }
  2376.           else if (strnicmp(currentline, "oberon", 6) == 0)
  2377.           { OutputType = TYPE_OBERON;
  2378.             currentline += 6;
  2379.           }
  2380.           else if (strnicmp(currentline, "e", 1)  ==  0)
  2381.           { OutputType = TYPE_E;
  2382.             ++currentline;
  2383.           }
  2384.           else if (strnicmp(currentline, "none", 4)  ==  0)
  2385.           { OutputType = TYPE_NONE;
  2386.             currentline += 4;
  2387.           }
  2388.           else
  2389.           { ShowWarn(msgUnknownStringType);
  2390.             currentline += strlen(currentline);
  2391.           }
  2392.           OverSpace(¤tline);
  2393.           if (*currentline)
  2394.           { ShowWarn(msgExtraCharacters);
  2395.           }
  2396.           continue;
  2397.         }
  2398.         else if (strnicmp(currentline, "shortstrings", 12) == 0)
  2399.         { currentline += 12;
  2400.           LongStrings = FALSE;
  2401.           OverSpace(¤tline);
  2402.           if (*currentline)
  2403.           { ShowWarn(msgExtraCharacters);
  2404.           }
  2405.           continue;
  2406.         }
  2407.       }
  2408.  
  2409.       currentline = line;
  2410.       while(*currentline)
  2411.       { bytesread = ReadChar(¤tline, bytes);
  2412.         if (bytesread)
  2413.         { if (*bytes == '%')
  2414.           { char c;
  2415.  
  2416.             switch(c = *(currentline++))
  2417.             { case 'b':
  2418.                 fputs(BaseName, fpout);
  2419.                 break;
  2420.               case 'n':
  2421.                 fprintf(fpout, "%d", NumStrings);
  2422.                 break;
  2423.               case 'v':
  2424.                 fprintf(fpout, "%d", CatVersion);
  2425.                 break;
  2426.               case 'l':
  2427.                 WriteString(fpout, Language, -1);
  2428.                 break;
  2429.               case 'f':
  2430.                 { char *tempstr;
  2431.  
  2432.                   if ((c = *currentline++) == 'v')
  2433.                   { fputs(VERS, fpout);
  2434.                   }
  2435.                   else
  2436.                   { tempstr = AllocFileName(CDFile, c - '0');
  2437.                     fputs(tempstr, fpout);
  2438.                   }
  2439.                 }
  2440.                 break;
  2441.               case 'o':
  2442.                 { char *tempstr;
  2443.  
  2444.                   tempstr = AllocFileName(SourceFile, *currentline++ - '0');
  2445.                   fputs(tempstr, fpout);
  2446.                 }
  2447.                 break;
  2448.               case 'i':
  2449.                 NeedRepeat = TRUE;
  2450.                 if (cs) fputs(cs->ID_Str, fpout);
  2451.                 break;
  2452.  
  2453.               case 'a':
  2454.               case 't':
  2455.  
  2456.               case 'd':
  2457.               case 'x':
  2458.               case 'c':
  2459.               case '0':
  2460.               case '1':
  2461.               case '2':
  2462.               case '3':
  2463.               case '4':
  2464.               case '5':
  2465.               case '6':
  2466.               case '7':
  2467.               case '8':
  2468.               case '9':
  2469.                   {
  2470.                   int len = 0;
  2471.  
  2472.                   while(c >= '0'  &&  c <= '9')
  2473.                     {
  2474.                     len = (c - '0') + len * 10;
  2475.                     c = *currentline++;
  2476.                     }
  2477.  
  2478.  
  2479.                   if(c ==  'a')
  2480.                     {
  2481.                     int _len = len ? len : 4;
  2482.                     char *start;
  2483.                     char _StrLen[20 + 1];
  2484.  
  2485.                     sprintf(_StrLen, "%020lx", cs->ID);
  2486.  
  2487.                     start = &_StrLen[20-_len*2];
  2488.                     while(_len>0)
  2489.                        {
  2490.                        fprintf(fpout, "\\x%.2s", start);
  2491.                        start+=2;
  2492.                        _len--;
  2493.                        }
  2494.                     }
  2495.  
  2496.                   if(c ==  't')
  2497.                     {
  2498.                     int _len = len ? len : 4;
  2499.                     char *start;
  2500.                     char _StrLen[20 + 1];
  2501.  
  2502.                     sprintf(_StrLen, "%020lx", ((CalcRealLength(cs->CD_Str) + 1) & 0xfffffe));
  2503.  
  2504.                     start = &_StrLen[20-_len*2];
  2505.                     while(_len>0)
  2506.                        {
  2507.                        fprintf(fpout, "\\x%.2s", start);
  2508.                        start+=2;
  2509.                        _len--;
  2510.                        }
  2511.                     }
  2512.  
  2513.                   if(c == 'c' || c == 'd' || c == 'x')
  2514.                     {
  2515.                     char buffer[20];
  2516.  
  2517.                     if(c == 'c') c = 'o';
  2518.  
  2519.                     if(len)
  2520.                       sprintf(buffer, "%%0%d%c", len, c);
  2521.                     else
  2522.                       sprintf(buffer, "%%%c", c);
  2523.  
  2524.                     if(cs) fprintf(fpout, buffer, cs->ID);
  2525.                     }
  2526.  
  2527.  
  2528.                   NeedRepeat = TRUE;
  2529.                   }
  2530.                   break;
  2531.  
  2532.               case 'e':
  2533.                 NeedRepeat = TRUE;
  2534.                 if (cs) fprintf(fpout, "%d", cs->Nr);
  2535.                 break;
  2536.               case 's':
  2537.                 NeedRepeat = TRUE;
  2538.                 if (cs)
  2539.                 { char *idstr;
  2540.                   unsigned long len = 0;
  2541.  
  2542.                   if (LengthBytes)
  2543.                   { idstr = cs->CD_Str;
  2544.                     while(*idstr)
  2545.                     { bytesread = ReadChar(&idstr, bytes);
  2546.                       if (bytesread)
  2547.                       { ++len;
  2548.                       }
  2549.                     }
  2550.                   }
  2551.                   WriteString(fpout, cs->CD_Str, LengthBytes ? len : -1);
  2552.                 }
  2553.                 break;
  2554.               case '(':
  2555.                 NeedRepeat = TRUE;
  2556.                 while(*currentline  &&  *currentline != ')')
  2557.                 { bytesread = ReadChar(¤tline, bytes);
  2558.                   if (bytesread  &&  cs  &&  cs->Next)
  2559.                   { putc((int) bytes[bytesread-1], fpout);
  2560.                   }
  2561.                 }
  2562.                 if (!*currentline)
  2563.                 { ShowWarn(msgNoTerminateBracket);
  2564.                 }
  2565.                 else
  2566.                 { ++currentline;
  2567.                 }
  2568.                 break;
  2569.  
  2570. // !!!! FIX !!!!
  2571.  
  2572.               case 'z':
  2573.                 {
  2574.                 int diff = (((CalcRealLength(cs->CD_Str) + 1) & 0xfffffe) - (CalcRealLength(cs->CD_Str)));
  2575.  
  2576.                 NeedRepeat = TRUE;
  2577.  
  2578.                 while(diff > 0)
  2579.                    {
  2580.                    fprintf(fpout, "\\x00");
  2581.                    diff--;
  2582.                    }
  2583.  
  2584.                 break;
  2585.                 }
  2586.  
  2587.               default:
  2588.                 { int c = *currentline++;
  2589.  
  2590.                   putc(c, fpout);
  2591.                 }
  2592.             }
  2593.           }
  2594.           else
  2595.           { putc((int) bytes[bytesread-1], fpout);
  2596.           }
  2597.         }
  2598.       }
  2599.       putc('\n', fpout);
  2600.     }
  2601.     while(NeedRepeat  &&  cs  &&  (cs = cs->Next));
  2602.  
  2603.     free(line);
  2604.   }
  2605.  
  2606.   fclose(fpin);
  2607.   fclose(fpout);
  2608. }
  2609. //|
  2610.  
  2611. /// FUNC: Usage
  2612. /*
  2613.     The Usage function describes the programs calling syntax.
  2614. */
  2615. void Usage(void)
  2616.  
  2617. {
  2618.   fputs((char *) msgUsageHead, stderr);
  2619.   fprintf(stderr, ": FlexCat CDFILE/A,CTFILE,CATALOG/K,NEWCTFILE/K,SOURCES/M,\n                WARNCTGAPS/S,NOOPTIM/S,FILL/S,FLUSH/S,NOBEEP/S,\n                QUIET/S,NOLANGTOLOWER/S,NOBUFFEREDIO/S,\n                MODIFIED/S,COPYMSGNEW/S,OLDMSGNEW/K, NOSPACE/S\n\n", VString);
  2620.   fprintf(stderr, "%s\n%s\n%s\n%s\n", msgUsage, msgUsage_2, msgUsage_3, msgUsage_4 );
  2621.   fprintf(stderr, "\n\n%s"
  2622. /*
  2623.   #ifdef _M68040
  2624.     " [040]"
  2625.   #else
  2626.     #ifdef _M68060
  2627.       " [060]"
  2628.     #else
  2629.       #ifdef _M68030
  2630.         " [030]"
  2631.       #else
  2632.         #ifdef _M68020
  2633.           " [020]"
  2634.         #else
  2635.           #ifdef _M68010
  2636.             " [010]"
  2637.           #endif
  2638.         #endif
  2639.       #endif
  2640.     #endif
  2641.   #endif
  2642. */
  2643.   "\n", VString);
  2644.  
  2645.  
  2646.   fprintf(stderr, "%s\n", EString);
  2647.   MyExit(5);
  2648. }
  2649. //|
  2650. /// FUNC: main
  2651. /*
  2652.     Finally the main function. Does nothing special except for scanning
  2653.     the arguments.
  2654. */
  2655. int main(int argc, char *argv [])
  2656. {
  2657.   char *cdfile, *ctfile, *newctfile, *catalog;
  2658.   char *source, *template;
  2659.   register int i;
  2660.  
  2661.   if(argc == 0)    /*  Aztec's entry point for workbench programs  */
  2662.    {
  2663.    fprintf(stderr, "FlexCat can't be run from Workbench!\n\n");
  2664.    fprintf(stderr, "Open a Shell session and type FlexCat ?\n");
  2665.    fprintf(stderr, "for more information\n");
  2666.    exit(5);
  2667.    }
  2668.  
  2669.   cdfile = ctfile = newctfile = catalog = NULL;
  2670.  
  2671.  
  2672.   /* let's open catalog files by hand if necessary */
  2673.   /* should be done automatically anyway for most  */
  2674.   /* cases, but, that depends on compiler...       */
  2675.  
  2676. #if defined(_DCC)
  2677.   // STATIC __autoinit VOID _STIOpenFlexCatCatalog(VOID)
  2678. #elif defined(__SASC)
  2679.   // VOID _STIOpenFlexCatCatalog(VOID)
  2680. #elif defined(__GNUC__)
  2681.   // VOID _STIOpenFlexCatCatalog(VOID)
  2682. #else
  2683.    OpenFlexCatCatalog();   /* no autoopen. we do it then */
  2684. #endif
  2685.  
  2686.  
  2687.     // Big Endian vs Little Endian (both supported ;-)
  2688.     if( !SwapChoose() )
  2689.        {
  2690.        fprintf(stderr, "FlexCat is unable to determine the\n");
  2691.        fprintf(stderr, "the byte order used by your system.\n");
  2692.        fprintf(stderr, "It's neither Little nor Big Endian?!.\n");
  2693.        exit(5);
  2694.        }
  2695.  
  2696.  
  2697.  
  2698. #if defined(__amigados)
  2699.   ReadPrefs();
  2700. #endif
  2701.  
  2702.   if(argc == 1)
  2703.     {
  2704.     Usage();
  2705.     }
  2706.  
  2707.   for (i = 1;  i < argc;  i++)
  2708.     {
  2709.     if(strnicmp (argv[i], "catalog=", 8) == 0)
  2710.       {
  2711.       catalog = argv[i] + 8;
  2712.       }
  2713.     else
  2714.     if(stricmp (argv[i], "catalog") == 0)
  2715.       {
  2716.       if(i+1 == argc)
  2717.         Usage();
  2718.       catalog = argv[++i];
  2719.       }
  2720.     else
  2721.     if(stricmp(argv[i], "nooptim") == 0)
  2722.      {
  2723.      NoOptim = TRUE;
  2724.      }
  2725.     else
  2726.     if(stricmp(argv[i], "fill") == 0)
  2727.      {
  2728.      Fill = TRUE;
  2729.      }
  2730.     else
  2731.     if(stricmp(argv[i], "quiet") == 0)
  2732.      {
  2733.      Quiet = TRUE;
  2734.      }
  2735.     else
  2736.     if(stricmp(argv[i], "flush") == 0)
  2737.      {
  2738.      DoExpunge = TRUE;
  2739.      }
  2740.     else
  2741.     if(stricmp(argv[i], "nobeep") == 0)
  2742.      {
  2743.      NoBeep = TRUE;
  2744.      }
  2745.     else
  2746.     if(stricmp(argv[i], "nobufferedio") == 0)
  2747.      {
  2748.      NoBufferedIO = TRUE;
  2749.      }
  2750.     else
  2751.     if (strnicmp (argv[i], "newctfile=", 10) == 0)
  2752.       {
  2753.       newctfile = argv[i] + 10;
  2754.       }
  2755.     else
  2756.     if(strnicmp (argv[i], "newctfile", 10) == 0)
  2757.       {
  2758.       if (i+1 == argc)
  2759.         Usage();
  2760.       newctfile = argv[++i];
  2761.       }
  2762.     else
  2763.     if(stricmp(argv[i], "nolangtolower") == 0)
  2764.       {
  2765.       LANGToLower = FALSE;
  2766.       }
  2767.     else
  2768.     if(stricmp(argv[i], "modified") == 0)
  2769.       {
  2770.       Modified = TRUE;
  2771.       }
  2772.     else
  2773.     if(stricmp(argv[i], "warnctgaps") == 0)
  2774.       {
  2775.       WarnCTGaps = TRUE;
  2776.       }
  2777.     else
  2778.     if(stricmp(argv[i], "copymsgnew") == 0)
  2779.       {
  2780.       CopyNEWs = TRUE;
  2781.       }
  2782.     else
  2783.     if(stricmp(argv[i], "nospace") == 0)
  2784.       {
  2785.       NoSpace = TRUE;
  2786.       }
  2787.     else
  2788.     if(stricmp(argv[i], "oldmsgnew") == 0)
  2789.       {
  2790.       sprintf( Old_Msg_New, "; %s", argv[++i] );
  2791.       }
  2792.     else
  2793.       if(cdfile == NULL)
  2794.         {
  2795.         if(stricmp(argv[i], "?") == 0 || stricmp(argv[i], "-h") == 0 || stricmp(argv[i], "help") == 0 || stricmp(argv[i], "--help") == 0)
  2796.           {
  2797.           Usage();
  2798.           }
  2799.         if(!ScanCDFile(cdfile = argv[i]))
  2800.           {
  2801.           MyExit(10);
  2802.           }
  2803.         }
  2804.     else
  2805.     if(strchr(argv[i], '='))
  2806.       {
  2807.       source = AllocString(argv[i]);
  2808.       *(template = strchr(source, '=')) = '\0';
  2809.       ++template;
  2810.  
  2811.       CreateSourceFile(source, template, cdfile);
  2812.       }
  2813.     else
  2814.       {
  2815.       if (ctfile)
  2816.         {
  2817.         Usage();
  2818.         }
  2819.       ctfile = argv[i];
  2820.       }
  2821.     }
  2822.  
  2823. #if defined(__amigados)
  2824.   if(Modified)
  2825.     {
  2826.     if(cdfile && ctfile && catalog)
  2827.        {
  2828.        long cd_time, ct_time, cat_time;
  2829.  
  2830.        if((cd_time = getft(cdfile)) != -1)
  2831.            {
  2832.            if((ct_time = getft(ctfile)) != -1)
  2833.               {
  2834.               if((cat_time = getft(catalog)) == -1)
  2835.                 cat_time = 0;
  2836.  
  2837.                 if((cat_time > ct_time) &&
  2838.                    (cat_time > cd_time))
  2839.                        {
  2840.                        if(!Quiet)
  2841.                          {
  2842.                          fprintf(stderr, (char *) msgUpToDate, catalog);
  2843.                          putc('\n', stderr);
  2844.                          }
  2845.  
  2846.                        MyExit(GlobalReturnCode);
  2847.                        }
  2848.                   else
  2849.                     {
  2850.                     if(!Quiet)
  2851.                       {
  2852.                       fprintf(stderr, "--> %s", catalog);
  2853.                       putc('\n', stderr);
  2854.                       }
  2855.                     }
  2856.               }
  2857.             else
  2858.               {
  2859.               ShowError(msgCantCheckDate, ctfile);
  2860.               }
  2861.            }
  2862.         else
  2863.            {
  2864.            ShowError(msgCantCheckDate, cdfile);
  2865.            }
  2866.        }
  2867.     }
  2868. #endif
  2869.  
  2870.   if(ctfile)
  2871.     {
  2872.     if(!ScanCTFile(ctfile))
  2873.       MyExit(10);
  2874.     }
  2875.  
  2876.   if(catalog)
  2877.     {
  2878.     if(!ctfile)
  2879.       {
  2880.       fprintf(stderr, (char *) msgNoCTArgument);
  2881.       Usage();
  2882.       }
  2883.     CreateCat(catalog);
  2884.     }
  2885.  
  2886.   if(newctfile)
  2887.     {
  2888.     CreateCTFile(newctfile);
  2889.     }
  2890.  
  2891.   MyExit(GlobalReturnCode);
  2892. }
  2893. //|
  2894. /// FUNC: wbmain
  2895.  
  2896. /*
  2897.     Dice's entry point for workbench programs
  2898. */
  2899. #if defined(__amigados)  &&  defined(_DCC)
  2900. void wbmain(struct WBStartup *wbmsg)
  2901. {
  2902.    fprintf(stderr, "FlexCat can't be run from Workbench!\n\n");
  2903.    fprintf(stderr, "Open a Shell session and type FlexCat\n");
  2904.    fprintf(stderr, "for syntax and more information\n");
  2905.  
  2906.    exit(5);
  2907. }
  2908. #endif
  2909. //|
  2910.